package com.svh.Controlador;

import com.clyme.filtro.Error.FiltroQueryException;
import com.clyme.filtro.Filtro;
import com.clyme.filtro.HibernateFiltro;
import com.svh.Entidad.Cliente;
import com.svh.Entidad.DetallePedido;
import com.svh.Entidad.Filtro.PedidoFiltro;
import com.svh.Entidad.Pedido;
import com.svh.Entidad.SubtipoProductoMarca;
import com.svh.Hibernate.HibernatePaginator;
import com.svh.Paginator.ClientePaginador;
import com.svh.Paginator.Paginador;
import com.svh.Paginator.PedidoPaginator;
import com.svh.Paginator.SubtipoProductoMarcaPaginator;
import com.svh.Reporte.ReporteIR;
import com.svh.Servicios.PedidoServicio;
import com.svh.Utils.ShortCondicion;
import com.svh.Utils.Utilitario;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.criterion.DetachedCriteria;
import org.primefaces.context.RequestContext;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.LazyDataModel;

/**
 *
 * @author Luis Alonso Ballena Garcia
 */
@ManagedBean(name = "pedidoControlador")
@ViewScoped
public class PedidoControlador {

    Date fechaMax;
    Pedido pedido;
    LazyDataModel<Cliente> clientes = null;
    LazyDataModel<Pedido> pedidos;
    PedidoServicio pedidoServicio = null;
    private String url;
    private PedidoFiltro pedidoFiltro;
    @ManagedProperty("#{sesionControlador}")
    SesionControlador sesionControlador;
    /**
     * Datos para la lista Producto*
     */
    LazyDataModel<SubtipoProductoMarca> subtipos;
    private int cantidad;
    private double total;
    private double precioActual;
    List<DetallePedido> misDetalles;
    SubtipoProductoMarca seleccionado;
    DetallePedido miDetalle;

    public PedidoControlador() {
    }

    public void initLista() {
        if (!FacesContext.getCurrentInstance().isPostback()) {
            sesionControlador.generarModulo(4);
            /**
             * NUMERO MAGICO T_T *
             */
            pedidos = new Paginador<Pedido>(new PedidoPaginator());
            pedidoFiltro = new PedidoFiltro();

        }
    }

    public void buscarFiltro() {
        HibernatePaginator hibernatepaginator = new PedidoPaginator(){
            @Override
            public void initFiltro() {
                super.initFiltro();
                try {
                    Filtro<DetachedCriteria> filtro = new HibernateFiltro(getFiltroCriteria());
                    filtro.addEquals("pedido.estado", pedidoFiltro.getEstado(), new ShortCondicion());
                    if(pedidoFiltro.getFechaRegistroMax() != null){
                        pedidoFiltro.setFechaRegistroMax(Utilitario.definirHoraMinuto(pedidoFiltro.getFechaRegistroMax(),23,59));
                    }
                    if(pedidoFiltro.getFechaEnvioMax() != null){
                        pedidoFiltro.setFechaEnvioMax(Utilitario.definirHoraMinuto(pedidoFiltro.getFechaEnvioMax(),23,59));
                    }
                    filtro.addRango("pedido.fechaRegistro", pedidoFiltro.getFechaRegistroMin(), pedidoFiltro.getFechaRegistroMax());
                    filtro.addRango("pedido.fechaEntrega", pedidoFiltro.getFechaEnvioMin(),pedidoFiltro.getFechaEnvioMax());
                    DetachedCriteria criteria = filtro.getQuery();
                    setFiltroCriteria(criteria);
                } catch (FiltroQueryException ex) {
                    Utilitario.LOG.error("Error en PerroControlador", ex);
                }

            }
        };
        pedidos = new Paginador<Pedido>(hibernatepaginator);
    }
    
    public void limpiarFiltro()
    {
        pedidos = new Paginador<Pedido>(new PedidoPaginator());
    }

    public void initRegistro() {
        if (!FacesContext.getCurrentInstance().isPostback()) {
            url = "create.xhtml?faces-redirect=true";
            fechaMax = new Date();
            clientes = new Paginador<Cliente>(new ClientePaginador());
            pedido = (Pedido) Utilitario.getFlash("pedido");
            pedido = (pedido == null) ? new Pedido() : pedido;
            Object listaDetalles = Utilitario.getFlash("misDetalles");
            misDetalles = (listaDetalles == null ? new ArrayList<DetallePedido>() : (List<DetallePedido>) listaDetalles);
            total = calcularTotal(total, misDetalles);
        }
    }

    public void initActualizar() {
        if (!FacesContext.getCurrentInstance().isPostback()) {
            url = "update.xhtml?faces-redirect=true";
            Object parameter = Utilitario.getFlash("idPedido");
            pedido = (Pedido) Utilitario.getFlash("pedido");
            if (parameter == null) {
                if (pedido == null) {
                    Utilitario.redireccionarJSF(FacesContext.getCurrentInstance(), "/views/pedido/list.xhtml");
                    return;
                }
            }
            clientes = new Paginador<Cliente>(new ClientePaginador());
            pedidoServicio = new PedidoServicio();
            if (pedido == null) {
                pedido = pedidoServicio.obtenerPedido((Integer) parameter);
            }
            pedido.setAuxFecha(pedido.getFechaEntrega());
            fechaMax = new Date();
            Object listaDetalles = Utilitario.getFlash("misDetalles");
            misDetalles = (listaDetalles == null ? new ArrayList<DetallePedido>(pedido.getDetallesPedidos()) : (List<DetallePedido>) listaDetalles);
            total = calcularTotal(total, misDetalles);
        }
    }

    public void initPesos() {
        if (!FacesContext.getCurrentInstance().isPostback()) {
            url = "update.xhtml?faces-redirect=true";
            Object parameter = Utilitario.getFlash("idPedido");
            pedido = (Pedido) Utilitario.getFlash("pedido");
            if (parameter == null) {
                if (pedido == null) {
                    Utilitario.redireccionarJSF(FacesContext.getCurrentInstance(), "/views/pedido/list.xhtml");
                    return;
                }
            }
            pedidoServicio = new PedidoServicio();
            if (pedido == null) {
                pedido = pedidoServicio.obtenerPedido((Integer) parameter);
            }
            pedido.setAuxFecha(pedido.getFechaEntrega());
            Object listaDetalles = Utilitario.getFlash("misDetalles");
            misDetalles = (listaDetalles == null ? new ArrayList<DetallePedido>(pedido.getDetallesPedidos()) : (List<DetallePedido>) listaDetalles);
            total = calcularTotalEnvio(total, misDetalles, true);
        }
    }

    public void initListaProductos() {
        if (!FacesContext.getCurrentInstance().isPostback()) {
            Object parametro = Utilitario.getFlash("pedido");
            if (parametro == null) {
                Utilitario.redireccionarJSF(FacesContext.getCurrentInstance(), "/views/pedido/list.xhtml");
                return;
            }
            Object dataUrl = Utilitario.getFlash("url");
            url = dataUrl.toString();
            pedido = (Pedido) parametro;
            seleccionado = new SubtipoProductoMarca();
            Object listaDetalles = Utilitario.getFlash("misDetalles");
            misDetalles = (ArrayList) listaDetalles;
            total = calcularTotal(total, misDetalles);
            subtipos = new Paginador<SubtipoProductoMarca>(new SubtipoProductoMarcaPaginator());
        }
    }

    public String irActualizar(int id) {
        Utilitario.putFlash("idPedido", id);
        return "update.xhtml?faces-redirect=true";
    }

    public String irPesos(int id) {
        Utilitario.putFlash("idPedido", id);
        return "peso.xhtml?faces-redirect=true";
    }

    public void registarPedido() {
        pedido.setFechaEntrega(pedido.getAuxFecha() != null ? new Timestamp(pedido.getAuxFecha().getTime()) : null);
        if (!esVistaValida()) {
            return;
        }
        pedido.setEstado(Pedido.PENDIENTE);
        pedido.setEmpleado(sesionControlador.getEmpleado());
        pedido.setIdUsuario(sesionControlador.getUsuario().getId());
        pedidoServicio = new PedidoServicio();
        pedidoServicio.registrarPedido(pedido, misDetalles);
        pedido = new Pedido();
        misDetalles = new ArrayList<DetallePedido>();
        total = calcularTotal(total, misDetalles);
    }

    public void actualizarPedido() {
        pedido.setFechaEntrega(pedido.getAuxFecha() != null ? new Timestamp(pedido.getAuxFecha().getTime()) : null);
        if (!esVistaValida()) {
            return;
        }
        
        pedidoServicio = new PedidoServicio();
        pedido.setIdUsuario(sesionControlador.getUsuario().getId());
        pedidoServicio.actualizarPedido(pedido, misDetalles, "Se ha actualizado correctamente");
        total = calcularTotal(total, misDetalles);
    }

    public void confirmarPedido() {
        pedido.setFechaEntrega(pedido.getAuxFecha() != null ? new Timestamp(pedido.getAuxFecha().getTime()) : null);
        if (!esVistaValida()) {
            return;
        }
        pedido.setEstado(Pedido.CONFIRMADO);
        pedidoServicio = new PedidoServicio();
        pedido.setIdUsuario(sesionControlador.getUsuario().getId());
        pedidoServicio.actualizarPedido(pedido, misDetalles, "El pedido se ha confirmado");
        total = calcularTotal(total, misDetalles);
    }

    public void actualizarPedidoPesos() {
        pedido.setFechaEntrega(pedido.getAuxFecha() != null ? new Timestamp(pedido.getAuxFecha().getTime()) : null);
        if (!esVistaValidaPesos()) {
            return;
        }
        pedido.setEstado(Pedido.ENVIO);
        pedidoServicio = new PedidoServicio();
        pedido.setIdUsuario(sesionControlador.getUsuario().getId());
        modificarDetallesPesos();
        pedidoServicio.actualizarPedido(pedido, misDetalles, "Se ha actualizado correctamente");
        total = calcularTotal(total, misDetalles);
    }

    public String denegarPedido() {
        pedidoServicio = new PedidoServicio();
        pedido.setEstado(Pedido.CANCELADO);
        pedido.setIdUsuario(sesionControlador.getUsuario().getId());
        pedidoServicio.actualizarPedido(pedido, "El pedido ha sido cancelado");
        return "list.xhtml?faces-redirect=true";
    }

    public void denegarPedidoList() {
        pedidoServicio = new PedidoServicio();
        pedido.setEstado(Pedido.CANCELADO);
        pedido.setIdUsuario(sesionControlador.getUsuario().getId());
        pedidoServicio.actualizarPedido(pedido, "El pedido ha sido cancelado");
    }

    public void agregarProductos() {
        RequestContext context = RequestContext.getCurrentInstance();
        if (!esAgregarValido()) {
            context.addCallbackParam("valido", false);
            return;
        }
        for (DetallePedido aux : misDetalles) {
            Integer idSubTipo = aux.getSubtipo().getId();
            if (idSubTipo.intValue() == seleccionado.getId().intValue()) {
                cantidad = 0;
                return;
            }
        }
        miDetalle = new DetallePedido();
        miDetalle.setSubtipo(seleccionado);
        miDetalle.setPrecio(seleccionado.getPrecio());
        miDetalle.setCantidad(cantidad);
        miDetalle.setPedido(pedido);
        cantidad = 0;
        misDetalles.add(miDetalle);
        total = calcularTotal(total, misDetalles);
        context.addCallbackParam("valido", true);
    }

    private double calcularTotal(double total, List<DetallePedido> detalles) {
        total = 0;
        if (detalles != null || detalles.isEmpty()) {
            for (DetallePedido detalle : detalles) {
                total += detalle.getCosto();
            }
        }
        return total;
    }

    private double calcularTotalEnvio(double total, List<DetallePedido> detalles, boolean before) {
        total = 0;
        if (detalles != null || detalles.isEmpty()) {
            for (DetallePedido detalle : detalles) {
                if (before) {
                    detalle.setPesoEnviado_aux(detalle.getCantidad() + "");
                }
                total += detalle.getCostoEnvio();
            }
        }
        return total;
    }

    public void calcularTotalEnvio_aux() {
        total = calcularTotalEnvio(total, misDetalles, false);
    }

    private void modificarDetallesPesos() {
        for (DetallePedido detalle : misDetalles) {
            detalle.setPesoEnviado(Double.parseDouble(detalle.getPesoEnviado_aux()));
        }
    }

    public void wrapperPrecio(double precio) {
        precioActual = new Double(precio);
    }

    public void wrapperPedido(SelectEvent event) {
        miDetalle = (DetallePedido) event.getObject();
    }

    public void eliminarPedido() {
        misDetalles.remove(miDetalle);
        total = calcularTotal(total, misDetalles);
    }

    private boolean esAgregarValido() {
        boolean resultado = true;
        if (!esPrecioValido()) {
            resultado = false;
        } else if (!esCantidadValida()) {
            Utilitario.enviarMensajeGlobalError("La cantidad no puede ser menor o igual que 0");
            resultado = false;
        }
        return resultado;
    }

    private boolean esPrecioValido() {
        if (seleccionado.getPrecio() < precioActual) {
            Utilitario.enviarMensajeGlobalError("El precio ingresado no debe ser menor que el precio actual");
            return false;
        }
        return true;
    }

    private boolean esCantidadValida() {
        return cantidad > 0;
    }

    public String irListaProductos() {
        Utilitario.putFlash("pedido", pedido);
        Utilitario.putFlash("url", url);
        Utilitario.putFlash("misDetalles", misDetalles);
        return "productos.xhtml?faces-redirect=true";
    }

    public String guardarLista() {
        Utilitario.putFlash("pedido", pedido);
        Utilitario.putFlash("misDetalles", misDetalles);
        return url;
    }

    private boolean esVistaValida() {
        boolean resultado = true;
        if (!esClienteValido()) {
            resultado = false;
        } else if (!esDireccionValida()) {
            resultado = false;
        } else if (!esFechaEntregaValido()) {
            resultado = false;
        } else if (!esProductoValido()) {
            Utilitario.enviarMensajeGlobalError("Debe agregar almenos un producto");
            resultado = false;
        }
        return resultado;
    }

    private boolean esVistaValidaPesos() {
        for (int i = 0; i < misDetalles.size(); i++) {
            if(!esPesoValido(misDetalles.get(i).getPesoEnviado_aux(), misDetalles.get(i).getCantidad(), i+1)){
                return false;
            } else if (!esCantidadValidaEnviada(misDetalles.get(i).getCantidad(), i + 1)) {
                return false;
            }
        }
        return true;
    }

    private boolean esClienteValido() {
        if (pedido.getCliente().getId() == null || pedido.getCliente().getId().intValue() == 0) {
            Utilitario.enviarMensajeGlobalError("Debe seleccionar un cliente");
            return false;
        }
        return true;
    }

    private boolean esDireccionValida() {
        boolean resultado = true;
        if (Utilitario.esNulo(pedido.getDireccion())) {
            Utilitario.enviarMensajeGlobalError("Debe ingresar la dirección de envio");
            resultado = false;
        }
        return resultado;
    }

    private boolean esFechaEntregaValido() {
        if (pedido.getFechaEntrega() == null) {
            Utilitario.enviarMensajeGlobalError("Debe ingresar la fecha de entrega");
            return false;
        }
        return true;
    }

    private boolean esProductoValido() {
        return misDetalles != null && !misDetalles.isEmpty();
    }
  
     private boolean esPesoValido(String peso, int cantidad, int i) {
        double prc = 0.2;
         System.out.println("////////////////");
         System.out.println(peso);
         System.out.println(cantidad);
         System.out.println(i);
        if (Utilitario.esSoloDecimalPositivo(peso)) {
            Utilitario.enviarMensajeGlobalError("El peso del Item " + i + " debe ser numerico y positivo");
            return false;
        }else if(Double.parseDouble(peso) < (cantidad * (1 - prc)) || Double.parseDouble(peso) > (cantidad * (1 + prc))){
            Utilitario.enviarMensajeGlobalError("El peso del Item "+ i +" debe estar en un rango de diferencia del "+ ((int) (prc*100)) + " %");
            return false;
        }
        return true;
    }

    private boolean esCantidadValidaEnviada(int cantidad, int i) {
        if (cantidad <= 0) {
            Utilitario.enviarMensajeGlobalError("La cantidad del Item " + i + " debe ser mayor a 0");
            return false;
        }
        return true;
    }

    public void exportarPDF(int idPedido) {
        try {
            HttpServletResponse httpServletResponse = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
            httpServletResponse.addHeader("Content-disposition", "attachment; filename=reporte_pedido.pdf");
            ServletOutputStream outputStream = httpServletResponse.getOutputStream();
            ReporteIR reportePedido = new ReporteIR();
            reportePedido.reporteDetPedido(idPedido, outputStream);
            FacesContext.getCurrentInstance().responseComplete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void capturarCliente(Cliente cliente) {
        pedido.setDireccion(cliente.getDireccion());
        pedido.setCliente(cliente);
    }

    /**
     * GETTERS AND SETTERS *
     */
    public LazyDataModel<Pedido> getPedidos() {
        return pedidos;
    }

    public void setPedidos(LazyDataModel<Pedido> pedidos) {
        this.pedidos = pedidos;
    }

    public void setSesionControlador(SesionControlador sesionControlador) {
        this.sesionControlador = sesionControlador;
    }

    public LazyDataModel<Cliente> getClientes() {
        return clientes;
    }

    public void setClientes(LazyDataModel<Cliente> clientes) {
        this.clientes = clientes;
    }

    public Pedido getPedido() {
        return pedido;
    }

    public void setPedido(Pedido pedido) {
        this.pedido = pedido;
    }

    public Date getFechaMax() {
        return fechaMax;
    }

    public void setFechaMax(Date fechaMax) {
        this.fechaMax = fechaMax;
    }

    public LazyDataModel<SubtipoProductoMarca> getSubtipos() {
        return subtipos;
    }

    public void setSubtipos(LazyDataModel<SubtipoProductoMarca> subtipos) {
        this.subtipos = subtipos;
    }

    public List<DetallePedido> getMisDetalles() {
        return misDetalles;
    }

    public void setMisDetalles(List<DetallePedido> misDetalles) {
        this.misDetalles = misDetalles;
    }

    public SubtipoProductoMarca getSeleccionado() {
        return seleccionado;
    }

    public void setSeleccionado(SubtipoProductoMarca seleccionado) {
        this.seleccionado = seleccionado;
    }

    public DetallePedido getMiDetalle() {
        return miDetalle;
    }

    public void setMiDetalle(DetallePedido miDetalle) {
        this.miDetalle = miDetalle;
    }

    public int getCantidad() {
        return cantidad;
    }

    public void setCantidad(int cantidad) {
        this.cantidad = cantidad;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public double getPrecioActual() {
        return precioActual;
    }

    public void setPrecioActual(double precioActual) {
        this.precioActual = precioActual;
    }

    public PedidoFiltro getPedidoFiltro() {
        return pedidoFiltro;
    }

    public void setPedidoFiltro(PedidoFiltro pedidoFiltro) {
        this.pedidoFiltro = pedidoFiltro;
    }
    
    

}
